/*
*    Qizx/open 3.0 beta
*
* This code is the open-source version of Qizx.
* Copyright (C) 2004-2009 Axyana Software -- All rights reserved.
*
* The contents of this file are subject to the Mozilla Public License 
*  Version 1.1 (the "License"); you may not use this file except in 
*  compliance with the License. You may obtain a copy of the License at
*  http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
*  for the specific language governing rights and limitations under the
*  License.
*
* The Initial Developer of the Original Code is Xavier Franc - Axyana Software.
*
*/
using System;
using System.Text.RegularExpressions;
using EvaluationException = System.Qizx.Api.EvaluationException;
using EvalContext = System.Qizx.XQuery.EvalContext;
using Focus = System.Qizx.XQuery.Focus;
using XQType = System.Qizx.XQuery.XQType;
using XQTypeException = System.Qizx.XQuery.XQTypeException;
using XQValue = System.Qizx.XQuery.XQValue;
using StringValue = System.Qizx.XQuery.Dt.StringValue;
using Expression = System.Qizx.XQuery.Op.Expression;
using Regex = System.Text.RegularExpressions.Regex;
using System.Qizx.Util;

namespace System.Qizx.XQuery.Fn
{
	
	/// <summary>  Implementation of function fn:tokenize.</summary>
	public class Tokenize: Matches
	{
		public override Prototype[] Protos
		{
			get
			{
				return protos;
			}
			
		}
		
		internal static Prototype[] protos;
		
		new public class Exec:Function.Call
		{
			
			internal Pattern precompiled;
			
			// precompile regexp if constant
			public override void  compilationHook()
			{
				Expression xflags = args.Length < 3?null:args[2];
				precompiled = System.Qizx.XQuery.Fn.Matches.precompileRegexp(args[1], xflags, false);
			}
			
			public override XQValue eval(Focus focus, EvalContext context)
			{
				string input = args[0].evalAsOptString(focus, context);
				if (input == null || input.Length == 0)
					return System.Qizx.XQuery.XQValues.Empty;
				context.at(this);
				
				Expression xflags = args.Length < 3?null:args[2];
				Pattern pat = precompiled != null?precompiled:System.Qizx.XQuery.Fn.Matches.compileRegexp(args[1], xflags, false, focus, context);
				
				return new Sequence(input, pat);
			}
		}
		
		
		internal class Sequence:StringValue
		{
			public override string ValueAsString
			{
				get
				{
					return current;
				}
				
			}
			override protected internal string Value
			{
				get
				{
					return current;
				}
				
			}
			
			internal string source, current;
			internal Regex regexp;
			internal MatchCollection _matchers;
			internal int lastStop = 0; // where the last match ends
			
			internal Sequence(string source, Regex regexp)
			{
				this.source = source;
				this.regexp = regexp;
				_matchers = regexp.Matches(source);
			}
			
			public override bool Next()
			{
				if (lastStop < 0)
				// there was no match at end
					return false;
                if(lastStop < _matchers.Count -1){
                    lastStop = lastStop + 1;
                }else if(lastStop == _matchers.Count -1){
                    lastStop = -1;
                }
				return true;
			}
			
			public override XQValue BornAgain()
			{
				return new Sequence(source, regexp);
			}
		}
		static Tokenize()
		{
			protos = new Prototype[]{Prototype.fn("tokenize", XQType.STRING.star, typeof(Exec)).arg("input", XQType.STRING.opt).arg("pattern", XQType.STRING), Prototype.fn("tokenize", XQType.STRING.star, typeof(Exec)).arg("input", XQType.STRING.opt).arg("pattern", XQType.STRING).arg("flags", XQType.STRING)};
		}
	}
}